package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	ws2 "sevlteServer/ws"
	"strconv"
	"sync"
	"time"
)

type MUser struct {
	id int
	ch chan bool
	ws *websocket.Conn
}

func (user *MUser) sendMsg() {
	replyMsg := ws2.WsMessage{Type: 3, From: strconv.Itoa(user.id),
		Msg: fmt.Sprintf("message%d", user.id)}
	js, _ := json.Marshal(&replyMsg)

	err := websocket.Message.Send(user.ws, js)
	if err != nil {
		user.ch <- false
		return
	}
}

func (user *MUser) request(api string) {
	requestUrl := "http://127.0.0.1:9999/api/" + api

	start := time.Now()
	response, err := http.Get(requestUrl)
	if err != nil {
		fmt.Println("request: " + err.Error())
		user.ch <- false
		close(user.ch)
		return
	}

	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			fmt.Println("close: " + err.Error())
			user.ch <- false
			close(user.ch)
			return
		}
	}(response.Body)

	if time.Since(start).Seconds() > 3 {
		fmt.Println("timeout", total)
		user.ch <- false
		close(user.ch)
	}
}

func (user *MUser) getFiles() {
	user.request("getfile")
}

func (user *MUser) uploadFile() {
	filename := fmt.Sprintf("file_%d", 1)

	file, err := os.Create(filename)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	_, err = file.Write([]byte("hello"))
	if err != nil {
		fmt.Println(err.Error())
		user.ch <- false
		return
	}

	bodyBuf := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuf)
	fileWriter, err := bodyWriter.CreateFormFile("files", filename)
	if err != nil {
		fmt.Println("error writing to buffer")
		user.ch <- false
		return
	}
	_, err = io.Copy(fileWriter, file)
	if err != nil {
		return
	}

	contentType := bodyWriter.FormDataContentType()
	err = bodyWriter.Close()
	if err != nil {
		fmt.Println(err.Error())
		user.ch <- false
		return
	}

	resp, err := http.Post("http://127.0.0.1:9999/api/fileupload", contentType, bodyBuf)
	if err != nil {
		fmt.Println(err.Error())
		user.ch <- false
		return
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			fmt.Println(err.Error())
			user.ch <- false
			return
		}
	}(resp.Body)

}

func (user *MUser) getUsers() {
	user.request("users")
}

func (user *MUser) init() {
	origin := "http://localhost/"
	url := "ws://localhost:9999/ws"
	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		fmt.Println(err.Error())
		ch <- false
		return
	}

	replyMsg := ws2.WsMessage{Type: 0, From: strconv.Itoa(user.id)}
	js, _ := json.Marshal(&replyMsg)

	err = websocket.Message.Send(ws, js)
	if err != nil {
		log.Fatal(err)
	}
	var msg string
	if err = websocket.Message.Receive(ws, &msg); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Received: %s.\n", msg)

	user.ws = ws
}

func (user *MUser) start() {
	defer w.Done()

	user.ch = make(chan bool, 1)

	for {
		select {
		case <-user.ch:
			lk.Lock()
			total -= 1
			lk.Unlock()
			fmt.Println("user total: ", total)
			ch <- false
			return
		case <-time.After(200 * time.Millisecond):
			{
				switch rand.Int() % 4 {
				case 0:
					user.getUsers()
					break
				case 1:
					user.getFiles()
					break
				case 2:
					user.uploadFile()
				case 3:
				}
			}
		}
	}
}

var w sync.WaitGroup
var lk sync.Mutex
var ch = make(chan bool, 1)
var total = 0

func main() {
	fmt.Println("start...")

	for range time.Tick(100 * time.Millisecond) {
		select {
		case <-ch:
			fmt.Println(total)
			goto end
		default:
			for i := 0; i < 100; i++ {
				user := MUser{id: total}
				w.Add(1)
				lk.Lock()
				total += 1
				lk.Unlock()
				go user.start()
			}
		}
	}
end:
	for {
		select {
		case <-ch:
		case <-time.After(5 * time.Second):
			goto finally
		}
	}

finally:

	fmt.Println("finish", total)
}
